package Methodes;

import DataIO.BinaireHydraulique;
import DataIO.BinaireThermique;
import DataIO.Data;
import DataIO.SolutionRecuit;

import java.security.SecureRandom;

/**
 * Classe appliquant la methode de résolution par le recuit sur notre modèle.
 * @author ejouini
 *
 */
public class Prob_Recuit extends Methode{
	
	/** Température courante */
	private int temperature;
	
	/** Nombre de paliers */
	private int paliers;
	
	/** Nombre d'itérations à effectuer */
	private int iterations;
	
	/**
	 * Constructeur initialisant les données du système et les différentes variables nécessaires
	 * au recuit.
	 * @param d : données générales du modèle.
	 * @param binaireT : données binaire des centrales thermique.
	 * @param binaireH : données binaire du reservoir hydrolique.
	 */
	public Prob_Recuit(Data d, BinaireThermique binaireT, BinaireHydraulique binaireH){
		binaireTherm = binaireT;
		binaireHydrau = binaireH;
		data = d;
		meilleureSolution = new SolutionRecuit();
		temperature = 1000;
		paliers = 10;
		iterations = 8;
	}
	
	/**
	 * Execute le recuit en initialisant le temps d'execution 
	 */
	public void solve(){
		long debut = System.currentTimeMillis();
		recuit();
		long fin = System.currentTimeMillis();
		double temps = (double)fin - debut;
		double[] maxCentrale1 = data.getMaxParCentrale().get(0);
		double[] maxCentrale2 = data.getMaxParCentrale().get(1);
		double[] maxCentrale3 = data.getMaxParCentrale().get(2);
		double[] maxCentrale4 = data.getMaxParCentrale().get(3);
		double[] maxCentrale5 = data.getMaxParCentrale().get(4);
		solution = new Solution(meilleureSolution.getProduction(), maxCentrale1, maxCentrale2, maxCentrale3,maxCentrale4,maxCentrale5,meilleureSolution.getFonctionObj(),temps);
	}
	
	/**
	 * Execute l'alogrithme du recuit
	 */
	public void recuit(){
		SolutionRecuit solCourante = new SolutionRecuit();
		solCourante.genererSolutionInitial(data, binaireTherm, binaireHydrau);
		meilleureSolution = solCourante;
		
		int mesIterations;
		double delta, alea;
		
		for( ; this.paliers > 0 ; --this.paliers){
			for(mesIterations = this.iterations ; mesIterations > 0 ; --mesIterations){
				SolutionRecuit monVoisin = new SolutionRecuit();
				monVoisin = solCourante.genererSolutionVoisine(data, binaireTherm, binaireHydrau);
				delta = monVoisin.getFonctionObj() - solCourante.getFonctionObj();
				if (delta < 0){
					solCourante = monVoisin;
				}
				else{
					SecureRandom sr = new SecureRandom();
					alea = sr.nextDouble();
					if(alea < Math.exp(-delta/temperature)) {
						solCourante = monVoisin;
					}
				}
			}
			temperature*=0.5;
		}
		meilleureSolution = solCourante;
		
	}
}
